;----------------------
;s16.asm
;编写一个新的7ch中断例程
;0清屏，1设置前景色，2设置背景色，3向上滚动一行
;参数： ah传递功能号 编号如标题
;      对于1，2 号功能，用al传送颜色
;----------------------
assume cs:code

code segment
    start:
        call copy_new_int7ch
        call set_new_int7ch
        ;设置参数        
        mov ah,2
        mov al,2
        ;中断调用
        int 7ch
        
        mov ax,4c00h
        int 21h
        
        ;通知编译器从200H开始重新计算标号
        org 200H   
    setscreen:  
        jmp  short set
        table dw sub1,sub2,sub3,sub4
    set:
        push bx

        cmp ah,3 ;判断功能编号是否大于3
        ja sert
        mov bl,ah
        mov bh,0
        add bx,bx ;根据ah中的功能号计算对应子程序在table中的偏移

        call word ptr table[bx]  ;调用对应的功能子程序
    sert: 
        pop bx
    	
        iret  ;CPU执行int 7ch指令进入中断例程之前，标志寄存器、当前的CS和IP被压入栈
		      ;在执行完中断例程后，应该用iret 指令恢复int 7ch执行前的标志寄存器和CS、IP的
    
;-----------------------------------------
;0清屏
;返回值： 无
;-----------------------------------------
    sub1:
        push bx
        push cx
        push es

        mov bx,0b800h
        mov es,bx
        mov bx,0
        mov cx,2000

    sub1s:
        mov byte ptr es:[bx],' '
        add bx,2
        loop sub1s

        pop es
        pop cx
        pop bx
        ret 
;-----------------------------------------
;1设置前景色
;参数： al 传递颜色 
;返回值： 无
;-----------------------------------------
    sub2:
        push bx
        push cx
        push es

        mov bx,0b800h
        mov es,bx
        mov bx,0
        mov cx,2000
    sub2s:
        and byte ptr es:[bx], 11111000b 
        or es:[bx],al
        add bx,2
        loop sub2s

        pop es
        pop cx
        pop bx
        ret
;-----------------------------------------
;2设置背景色
;参数 al 传递颜色 
;返回值： 无
;-----------------------------------------
    sub3:
        push bx
        push cx
        push es

        mov cl,4
        shl al,cl
        mov bx,0b800h
        mov es,bx
        mov bx,1
        mov cx,2000

    sub3s:
        and byte ptr es:[bx], 10001111b 
        or es:[bx],al
        add bx,2
        loop sub3s

        pop es
        pop cx
        pop bx
        ret
;-----------------------------------------
;3向上滚动一行
;参数： 无
;返回值： 无
;-----------------------------------------
    sub4:
        push cx
        push si
        push di 
        push es
        push ds

        mov si,0b800h
        mov es,si
        mov ds,si
        mov si,160 ;ds:si指向地n+1行
        mov di,0   ;es:di指向第n行
        cld 
        mov cx,24

    sub4s:
        push cx
        mov cx,160
        rep movsb ;复制
        pop cx
        loop sub4s

        mov cx,80
        mov si,0
    sub4s1:
        mov byte ptr [160*24+si],' ' ;最后一行
        add si,2
        loop sub4s1

        pop ds
        pop es
        pop di
        pop si
        pop cx
        ret
    setscreen_end: nop                                            
    set_new_int7ch:
        mov ax,0
        mov es,ax
        
        mov word ptr es:[7ch*4], 200h
        mov word ptr es:[7ch*4+2], 0

        ret
    copy_new_int7ch:
        mov ax,cs
        mov ds,ax
        mov si,offset setscreen					;设置ds:si指向源地址

        mov ax,0
        mov es,ax
        mov di,200h							;设置es:di指向目的地址
        
        mov cx,offset setscreen_end -  setscreen	;设置cx为传输长度
        cld									;设置传输方向为正
        rep movsb

        ret
        
code ends
end start